package com.scy.desAes;

import org.apache.commons.codec.binary.Base64;

import javax.crypto.Cipher;
import javax.crypto.spec.IvParameterSpec;
import javax.crypto.spec.SecretKeySpec;

/**
 * DesAesDemo
 *
 * @Author: 马伟奇
 * @CreateTime: 2020-05-05
 * @Description: 对称加密
 */
public class DesAesDemo {

    public static final String IV_KEY = "123456aa";

    public static void main(String[] args) throws Exception {
        // 原文 如果使用的是不填充的模式，那么原文必须是8个字节的整数倍
        String plainText = "硅谷123";
        // 定义key
        // 如果使用des进行加密，那么密钥必须是8个字节
        String desPassword = "1234abcd";
        // 算法 qANksk5lvqM=
//        String transformation = "DES";
        // ECB:表示加密模式
        // PKCS5Padding:表示填充模式 qANksk5lvqM=
//        String transformation = "DES/ECB/PKCS5Padding";
        // 如果默认情况，没有写填充模式和加密模式，那么默认就使用DES/ECB/PKCS5Padding
//        8Ze/OtPlSaU=
        String transformation = "DES/CBC/PKCS5Padding";
        //Y6htKI/ceJg=
//        String transformation = "DES/CBC/PKCS5Padding";
        // 加密类型
        String algorithm = "DES";
        // 指定获取密钥的算法
        String encryptDES = encryptDES(plainText, desPassword, transformation, algorithm);
        System.out.println("加密:" + encryptDES);

        String s = decryptDES(encryptDES, desPassword, transformation, algorithm);
        System.out.println("解密:" + s);
    }

    /**
     * 解密
     *
     * @param cipherTextEncryptByDES     密文
     * @param desPassword            密钥
     * @param transformation 加密算法
     * @param algorithm      加密类型
     * @return
     */
    private static String decryptDES(String cipherTextEncryptByDES, String desPassword, String transformation, String algorithm) throws Exception {

        Cipher cipher = Cipher.getInstance(transformation);

        SecretKeySpec secretKeySpec = new SecretKeySpec(desPassword.getBytes(), algorithm);

        if (transformation.toLowerCase().contains("cbc")) {
            //说明是cbc模式,需要添加iv向量
            // 创建iv向量
            IvParameterSpec iv = new IvParameterSpec(IV_KEY.getBytes());
            //Cipher.DECRYPT_MODE:表示解密
            // 解密规则
            cipher.init(Cipher.DECRYPT_MODE, secretKeySpec, iv);
        } else {
            //说明是ecb模式,不需要iv向量
            cipher.init(Cipher.DECRYPT_MODE, secretKeySpec);
        }

        // 解密，传入密文
        byte[] bytes = cipher.doFinal(Base64.decodeBase64(cipherTextEncryptByDES));

        return new String(bytes);
    }

    /**
     * 使用DES加密数据
     *
     * @param plainText          : 原文
     * @param desPassword            : 密钥(DES,密钥的长度必须是8个字节)
     * @param transformation : 获取Cipher对象的算法
     * @param algorithm      : 获取密钥的算法
     * @return : 密文
     * @throws Exception
     */
    private static String encryptDES(String plainText, String desPassword, String transformation, String algorithm) throws Exception {
        // 获取加密对象
        Cipher cipher = Cipher.getInstance(transformation);

        // 创建加密规则
        // 第一个参数key的字节
        // 第二个参数表示加密算法
        SecretKeySpec sks = new SecretKeySpec(desPassword.getBytes(), algorithm);

        if (transformation.toLowerCase().contains("cbc")) {
            //说明是cbc模式,需要提供iv向量
            // 创建iv向量，iv向量，是使用到CBC加密模式
            // 在使用iv向量进行加密的时候，iv的字节也必须是8个字节
            IvParameterSpec iv = new IvParameterSpec(IV_KEY.getBytes());
            // ENCRYPT_MODE：加密模式
            // DECRYPT_MODE: 解密模式
            // 初始化加密模式和算法
            cipher.init(Cipher.ENCRYPT_MODE, sks, iv);
        } else {
            //说明是ecb模式,不需要iv向量
            cipher.init(Cipher.ENCRYPT_MODE, sks);
        }


        // 加密
        byte[] bytes = cipher.doFinal(plainText.getBytes());

        // 输出加密后的数据
        String encode = Base64.encodeBase64String(bytes);

        return encode;
    }
}